package pl.edu.romanow.model

import net.liftweb.util.Helpers
import net.liftweb.http.SessionVar
import net.liftweb.common.{Empty, Full, Box}
import net.liftweb.json.{DefaultFormats, JsonParser}
import net.liftweb.http.js.{JsCmds, JsCmd}
import net.liftweb.json.JsonAST.JObject
import pl.edu.romanow.Crawler
import com.tinkerpop.blueprints.pgm.Vertex
import pl.edu.romanow.dispatch.{FacebookDispatch, FacebookJob}
import pl.edu.romanow.util.HTMLUtil
import pl.edu.romanow.dispatch.FacebookDispatch.{FacebookSuccess, FacebookJobReq}

/**
 * Created by IntelliJ IDEA.
 * User: jar
 * Date: 27.03.12
 * Time: 10:22
 * To change this template use File | Settings | File Templates.
 */


object Facebook {

  object currentAccessToken extends SessionVar[Box[String]](Empty)

  object currentUser extends SessionVar[Box[FacebookUser]](Empty) {
    override def is = super.is match {
      case f: Full[FacebookUser] => f
      case _ if !currentAccessToken.is.isEmpty => FacebookDispatch.processFacebookJob(CurrentUserJob, HTMLUtil.refreshParent) match {
        case _: FacebookSuccess => super.is
        case _ => Empty
      }
      case _ => Empty
    }
  }

  def queryData: JsCmd = JsCmds.Noop

  def dataQueried_? = false

  def fullCrawl() = {

    val id = currentUser.openTheBox.id

    val mgr = Database.appCon

    val token = currentAccessToken.is.open_!

    Crawler ! new FriendsListJob(id, token, mgr)
    Crawler ! new UserInfoJob(id, mgr, token)
  }

  def currentFacebookNode: Box[Vertex] = {
    Full(Database.appCon.findVOrCreateById("Facebook", Facebook.currentUser.openOr(return Empty).id))
  }


  def showFacebookMenu: JsCmd = JsCmds.Noop

}

object FacebookUtil {

  def access_token(data: String): Box[String] =
    if (data.startsWith("access_token=") && data.length() > "access_token=".length())
      Full(data.replaceFirst("access_token=", ""))
    else
      Empty
}


case class FacebookUser(name: String, id: String) {
  val imgUrl = "https://graph.facebook.com/%s/picture".format(id)
}

object CurrentUserJob extends FacebookJob {

  implicit val formats = DefaultFormats


  override def handleResponse(data: String): Box[String] = {
    Helpers.tryo(JsonParser.parse(data).extract[FacebookUser]) match {
      case Full(data) =>
        Facebook.currentUser(Full(data))
        None;
      case _ => Full("bad data: " + data)
    }
  }

  override def name: String = "loggedUserDataToDisplay"

  override def createUrl(accessToken: String): String = graphUrl + "/me?fields=name,id&access_token=%s".format(accessToken)

}


class UserInfoJob(id: String, mgr: ConnectionManager, override val token: String) extends FacebookJob with FacebookJobReq {


  override val job: FacebookJob = this

  override def handleResponse(data: String): Box[String] = {
    JsonParser.parse(data) match {
      case obj: JObject =>
        JsonObjectManager.mangeObject(obj, mgr, "Facebook");
        Crawler ! new ConnectionListJob(id, token, mgr)
        Empty
      case _ => Full("Bad data")
    }
  }

  override def name: String = "objectInfo " + id

  override def createUrl(accessToken: String): String = graphUrl + "/%s?&access_token=%s".format(id, accessToken)

}

class ConnectionJob(id: String, connection: String, override val token: String, mgr: ConnectionManager)
  extends FacebookJob with FacebookJobReq {

  override val job: FacebookJob = this

  override def handleResponse(data: String): Box[String] = {
    JsonParser.parse(data) match {
      case obj: JObject => JsonObjectManager.manageConnection(id, connection, obj, mgr, "Facebook");
      Empty
      case _ => Full("Bad data")
    }
  }

  override def name: String = "connectionInfo " + id + " connection " + connection

  override def createUrl(accessToken: String): String = graphUrl + "/%s/%s?&access_token=%s".format(id, connection, accessToken)

}


class ConnectionListJob(id: String, override val token: String, mgr: ConnectionManager) extends FacebookJob with FacebookJobReq {

  def prepareConnections(conn: Seq[String]): Seq[String] = {
    (conn ++ ("friends" :: "likes" :: Nil)).filter(s => ("permissions" :: "mutualfriends" :: Nil).contains(s))
    "likes" :: "feed" :: "links" :: "groups" :: "posts" :: Nil
    // "likes" :: Nil;
  }

  override val job: FacebookJob = this

  override def handleResponse(data: String): Box[String] = {
    JsonParser.parse(data) match {
      case obj: JObject =>
        Crawler ! prepareConnections(JsonObjectManager.allConnections(obj)).map(new ConnectionJob(id, _, token, mgr))
        Empty
      case _ => Full("Bad data")
    }
  }

  override def name: String = "connection List for: " + id

  override def createUrl(accessToken: String): String = graphUrl + "/%s?&access_token=%s&metadata=1".format(id, accessToken)

}


class FriendsListJob(id: String, override val token: String, mgr: ConnectionManager) extends FacebookJob with FacebookJobReq {


  override val job: FacebookJob = this

  override def handleResponse(data: String): Box[String] = {
    JsonParser.parse(data) match {
      case obj: JObject =>
        JsonObjectManager.manageFriends(id, obj, mgr, "Facebook").foreach {
          id =>
            Crawler ! new MutualFriendsJob(id, token, mgr)
            Crawler ! new UserInfoJob(id, mgr, token)
        }
        Empty
      case _ => Full("Bad data" + data)
    }
  }

  override def name: String = "Freinds List for " + id

  override def createUrl(accessToken: String): String = graphUrl + "/%s/friends?&access_token=%s".format(id, accessToken)

}

class MutualFriendsJob(id: String, override val token: String, mgr: ConnectionManager) extends FacebookJob with FacebookJobReq {


  override val job: FacebookJob = this

  override def handleResponse(data: String): Box[String] = {
    JsonParser.parse(data) match {
      case obj: JObject =>
        JsonObjectManager.manageMutualFriends(id, obj, mgr, "Facebook")
        Empty
      case _ => Full("Bad data" + data)
    }
  }

  override def name: String = "Mutual Friendslist List for " + id

  override def createUrl(accessToken: String): String = graphUrl + "/me/mutualfriends?user=%s&access_token=%s".format(id, accessToken)

}